/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#include "Object.h"

namespace liba
{
namespace lib2d
{
namespace gui
{

Object::Object( Object * parent, const Rect & window_rect )
:	parent( 0 ),
	focus_object( 0 ),
	in_focus( false ),
	mouse_pressed( false ),
	last_move( 0 ),
	window_rect( window_rect ),
	client_rect( window_rect )//TODO
{
	change_parent( parent );
	view = new view::Object( this );
}

Object::~Object()
{
	change_parent( 0 );

	while( children.size() )
		delete *begin();
}

void Object::on_focus( bool focus )
{
	in_focus = focus;
	if( !in_focus && focus_object )
	{
		focus_object->on_focus( false );
		focus_object = 0;
	}
}

void Object::change_parent( Object * new_parent )
{
	if( parent )
		parent->erase( parent_it );
	parent = new_parent;
	if( parent )
		parent_it = parent->insert( this );
}

Object::iterator Object::insert( Object * obj )
{
	return children.insert( children.begin(), obj );
}

void Object::erase( iterator it )
{
	if( *it == last_move )
		last_move = 0;
	if( *it == focus_object )
		focus_object = 0;

	children.erase( it );
}

void Object::on_text( const std::wstring & text )
{
	if( focus_object )
		focus_object->on_text( text );
}

void Object::on_key_down( const std::string & key_name )
{
	if( focus_object )
		focus_object->on_key_down( key_name );
}

void Object::life_cycle( double delta_time )
{
	for( iterator it = begin(); it != end(); ++it )
		(*it)->life_cycle( delta_time );
}

void Object::on_mouse_out()
{
	if( last_move )
		last_move->on_mouse_out();
	last_move = 0;
}

void Object::on_button_down( const Vector2 & point, const Atom & button_name )
{
	in_focus = true;
	mouse_pressed = true;
	for( iterator it = begin(); it != end(); ++it )
	{
		Object * obj = *it;
		if( obj->get_window_rect().is_intersects( point ) )
		{
			if( focus_object )
				focus_object->on_focus( false );
			focus_object = obj;
			focus_object->on_focus( true );

			//move focus object to top
			children.remove( focus_object );
			children.push_front( focus_object );
			focus_object->parent_it = children.begin();

			obj->on_button_down( point - obj->get_window_rect().get_coord(), button_name );
			return;
		}
	}
	if( focus_object )
		focus_object->on_focus( false );
	focus_object = 0;
}

void Object::on_button_up( const Vector2 & point, const Atom & button_name )
{
	mouse_pressed = false;
	for( iterator it = begin(); it != end(); ++it )
	{
		Object * obj = *it;
		if( obj->get_window_rect().is_intersects( point ) )
		{
			if( focus_object && focus_object != obj )
			{
//				focus_object->on_focus( false );
				focus_object->on_button_up( point - focus_object->get_window_rect().get_coord(), button_name );
//				focus_object = 0;
				obj->on_mouse_move( point - obj->get_window_rect().get_coord() );
				last_move = obj;
			}
			obj->on_button_up( point - obj->get_window_rect().get_coord(), button_name );
			return;
		}
	}

	if( focus_object )
	{
		focus_object->on_button_up( point - focus_object->get_window_rect().get_coord(), button_name );
//		focus_object->on_focus( false );
//		focus_object = 0;
	}
}

void Object::on_mouse_move_outside( const Vector2 & point )
{
	for( iterator it = begin(); it != end(); ++it )
		(*it)->on_mouse_move_outside( point - (*it)->get_window_rect().get_coord() );
}

void Object::on_mouse_move( const Vector2 & point )
{
	if( focus_object && mouse_pressed )
	{
		if( focus_object->get_window_rect().is_intersects( point ) )
		{
			focus_object->on_mouse_move( point - focus_object->get_window_rect().get_coord() );
			last_move = focus_object;
		}
		else
		{
			Object::on_mouse_out();
			focus_object->on_mouse_move_outside( point - focus_object->get_window_rect().get_coord() );
		}
		return;
	}

	for( iterator it = begin(); it != end(); ++it )
	{
		Object * obj = *it;
		if( obj->get_window_rect().is_intersects( point ) )
		{
			if( last_move && last_move != obj )
				last_move->on_mouse_out();
			obj->on_mouse_move( point - obj->get_window_rect().get_coord() );
			last_move = obj;
			return;
		}
	}
	Object::on_mouse_out();
}

view::Object * Object::get_view()const
{
	return view;
}

void Object::layout()
{
	for( iterator it = begin(); it != end(); ++it )
		(*it)->layout();
}

} //namespace gui
} //namespace lib2d
} //namespace liba

